/*
 * @filename BaseService.java
 * @author barry
 * @version 0.0.1
 * @date 2019年12月11日
 */
package com.bnzj.core.persistence;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.Query;
import javax.persistence.Table;
import javax.transaction.Transactional;

import com.bnzj.core.persistence.query.QueryHelpBean;
import com.bnzj.core.persistence.query.QueryService;
import com.bnzj.core.persistence.query.conversion.CaseFormat;
import com.bnzj.core.persistence.repository.BaseRepository;
import com.bnzj.core.rest.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.StringUtils;

/**
 * @author barry
 * @date 2019-12-11
 */
public abstract class BaseService<R extends BaseRepository<T, ID>, T, ID extends Serializable> {

    @Autowired
    protected R repository;

    @Autowired
    protected QueryService queryService;

    protected Class<T> entityClass;

    protected String tableName;

    @SuppressWarnings("unchecked")
    protected BaseService() {
        Type type = getClass().getGenericSuperclass();
        Type trueType = ((ParameterizedType) type).getActualTypeArguments()[1];
        this.entityClass = (Class<T>) trueType;
        Table table = entityClass.getAnnotation(Table.class);
        String tableName = null;
        if(table != null) {
            tableName = table.name();
        }else {
            Entity entity = entityClass.getAnnotation(Entity.class);
            if(!StringUtils.isEmpty(entity.name())) {
                tableName = entity.name();
            }else {
                tableName = entityClass.getSimpleName();
            }
            tableName = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, tableName);
        }
        this.tableName = tableName;
    }

    @Transactional
    public T save(T entity) {
        return repository.save(entity);
    }

    @Transactional
    public T saveAndFlush(T entity) {
        return repository.saveAndFlush(entity);
    }

    @Transactional
    public List<T> saveAll(Iterable<T> list) {
        return repository.saveAll(list);
    }

    /**
     * 物理删除
     * @param id
     */
    @Transactional
    @CacheEvict
    public void delete(ID id) {
        repository.deleteById(id);
    }

    /**
     * 逻辑删除
     * @param id
     */
    @Transactional
    @CacheEvict
    public void logicDelete(ID id, String modifyBy, String modifyName) {
        repository.logicDelete(id, modifyBy, modifyName, new Date());
    }

    /**
     * 禁用
     * @param id
     */
    @Transactional
    public void disable(ID id, String modifyBy, String modifyName) {
        repository.disable(id, modifyBy, modifyName, new Date());
    }

    /**
     * 切换删除状态
     * @param id
     */
    @Transactional
    public int switchDeleteState(ID id, String modifyBy, String modifyName) {
        String sql = "update " + tableName + " set deleted = !deleted, modify_by = :modifyBy, modify_name = :modifyName, modify_time = :modifyTime where id = :id";
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("id", id);
        map.put("modifyBy", modifyBy);
        map.put("modifyName", modifyName);
        map.put("modifyTime", new Date());
        return queryService.createNativeQuery(sql, map).executeUpdate();
    }

    /**
     * 切换启用状态
     * @param id
     */
    @Transactional
    public int switchEnableState(ID id, String modifyBy, String modifyName) {
        String sql = "update " + tableName + " set enabled = !enabled, modify_by = :modifyBy, modify_name = :modifyName, modify_time = :modifyTime where id = :id";
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("id", id);
        map.put("modifyBy", modifyBy);
        map.put("modifyName", modifyName);
        map.put("modifyTime", new Date());
        return queryService.createNativeQuery(sql, map).executeUpdate();
    }

    @Transactional
    public void deleteAll(List<ID> list) {
        list.forEach(id -> repository.deleteById(id));
    }

    public long counts(){
        return repository.count();
    }

    public boolean exists(T entity){
        //精确查询
        ExampleMatcher exampleMatcher = ExampleMatcher.matching().withStringMatcher(ExampleMatcher.StringMatcher.EXACT).withIgnoreNullValues();
        Example<T> example = Example.of(
                , exampleMatcher);
        return repository.count(example) > 0;
    }

    public boolean exists(ID id){
        return repository.existsById(id);
    }

    //@Cacheable(key = "#root.targetClass+'---'+#root.methodName+'---'+#p0", sync=true)
    public Optional<T> findById(ID id) {
        return repository.findById(id);
    }

    public Set<ID> findAllId(){
        return repository.findAllId();
    }

    public List<T> findAllById(Iterable<ID> ids){
        return repository.findAllById(ids);
    }

    //@Cacheable(key = "#root.targetClass+'---'+#root.methodName+'---'+#p0", sync=true)
    public Optional<T> findOne(T entity) {
        //设置为精确搜索(仅对于String类型)，忽略空值
        ExampleMatcher exampleMatcher = ExampleMatcher.matching()
                .withStringMatcher(ExampleMatcher.StringMatcher.EXACT).withIgnoreNullValues();
        Example<T> example = Example.of(entity, exampleMatcher);
        return repository.findOne(example);
    }

    @SuppressWarnings("unchecked")
    public <V> V getSingleResult(String sql, Map<String, Object> paramsMap) {
        Query query = queryService.createNativeQuery(sql, paramsMap);
        return (V)query.getSingleResult();
    }

    public List<T> findAll() {
        return repository.findAll();
    }

    public List<T> findAll(Sort sort) {
        return repository.findAll(sort);
    }

    public List<T> findAll(T entity) {
        //设置为尾部模糊搜索(仅对于String类型)，忽略空值
        ExampleMatcher exampleMatcher = ExampleMatcher.matching()
                .withStringMatcher(ExampleMatcher.StringMatcher.STARTING).withIgnoreNullValues();
        return findAll(entity, exampleMatcher);
    }

    public List<T> findAll(T entity, ExampleMatcher exampleMatcher) {
        Example<T> example = Example.of(entity, exampleMatcher);
        return repository.findAll(example);
    }

    public Page<T> findPage(T entity, ExampleMatcher exampleMatcher, Pageable pageable) {
        Example<T> example = Example.of(entity, exampleMatcher);
        return repository.findAll(example, pageable);
    }

    public Page<T> findPage(T entity, Pageable pageable) {
        //设置为尾部模糊搜索(仅对于String类型)，忽略空值
        ExampleMatcher exampleMatcher = ExampleMatcher.matching()
                .withStringMatcher(ExampleMatcher.StringMatcher.STARTING).withIgnoreNullValues();
        return findPage(entity, exampleMatcher, pageable);
    }

    public int getCounts(QueryHelpBean bean) {
        return queryService.getCounts(bean);
    }

    public <V> Page<V> findAll(QueryHelpBean bean) {
        return queryService.findAll(bean);
    }

    public <V> List<V> exportAll(QueryHelpBean bean) {
        return queryService.exportAll(bean);
    }

    /**
     * @Description:数据查询根据角色Code获取权限范围数据
     * @param roleCode
     * @return
     */
    public static String getDatePerm(List<String> roleCodeList,String supplierId,List<String> projectIdList,List<Long> deptIdList) {
    	String whereBasicSql = "";
    	String projectId = "";
    	String deptIds = "";
    	for(String roleCode : roleCodeList) {
    		if("supplier".equals(roleCode)) { //如果是供应商角色
    			if(!org.apache.commons.lang3.StringUtils.isEmpty(supplierId)) {
    				if(!org.apache.commons.lang3.StringUtils.isEmpty(whereBasicSql)) {
    					whereBasicSql += " or t.supplierId='"+supplierId+"' ";
    				} else {
    					whereBasicSql += " and t.supplierId='"+supplierId+"' ";
    				}
    			}
    		}
    		if("pm".equals(roleCode)) { //如果是项目经理角色
    			for(String pid : projectIdList) {
    				projectId += pid + ",";
    			}
    			if(!org.apache.commons.lang3.StringUtils.isEmpty(projectId)) {
    				projectId = projectId.substring(0, projectId.length() - 1);
    				if(!org.apache.commons.lang3.StringUtils.isEmpty(whereBasicSql)) {
    					whereBasicSql += " or t.projectId in ("+projectId+") ";
    				} else {
    					whereBasicSql += " and t.projectId in ("+projectId+") ";
    				}
    			}
    		}
    	}
    	if(roleCodeList.size() > 0) {
    		for(Long deptId : deptIdList) {
    			deptIds += deptId + ",";
    		}
        	if(!org.apache.commons.lang3.StringUtils.isEmpty(deptIds)) {
        		deptIds = deptIds.substring(0, deptIds.length()-1);
        	}
    		if(!org.apache.commons.lang3.StringUtils.isEmpty(deptIds)) {
    			if(!org.apache.commons.lang3.StringUtils.isEmpty(whereBasicSql)) {
    				whereBasicSql += " or t.deptId in ("+deptIds+") ";
    			} else {
    				whereBasicSql += " and t.deptId in ("+deptIds+") ";
    			}
    		}
        	if(org.apache.commons.lang3.StringUtils.isEmpty(whereBasicSql)) {
    			whereBasicSql += " and 1!=1 ";
    		}
    	}
    	return whereBasicSql;
    }

    /**
     * @Description:数据统计根据角色Code获取权限范围数据
     * @param roleCodeList
     * @param supplierId
     * @param projectCode
     * @return
     */
    public static String getCountDatePerm(List<String> roleCodeList,String supplierId,List<String> projectIdList,List<Long> deptIdList) {
    	String whereCountBasicSql = "";
    	String projectId = "";
    	String deptIds = "";
    	for(String roleCode : roleCodeList) {
    		if("supplier".equals(roleCode)) { //如果是供应商角色
    			if(!org.apache.commons.lang3.StringUtils.isEmpty(supplierId)) {
    				if(!org.apache.commons.lang3.StringUtils.isEmpty(whereCountBasicSql)) {
    					whereCountBasicSql += " or g.id='"+supplierId+"' ";
    				} else {
    					whereCountBasicSql += " and g.id='"+supplierId+"' ";
    				}
    			}
    		}
    		if("pm".equals(roleCode)) { //如果是项目经理角色
    			for(String pid : projectIdList) {
    				projectId += pid + ",";
    			}
    			if(!org.apache.commons.lang3.StringUtils.isEmpty(projectId)) {
    				projectId = projectId.substring(0, projectId.length() - 1);
    				if(!org.apache.commons.lang3.StringUtils.isEmpty(whereCountBasicSql)) {
    					whereCountBasicSql += " or b.current_item_number in ("+projectId+") ";
    				} else {
    					whereCountBasicSql += " and b.current_item_number in ("+projectId+") ";
    				}
    			}
    		}
    	}
    	if(roleCodeList.size() > 0) {
    		for(Long deptId : deptIdList) {
    			deptIds += deptId + ",";
    		}
        	if(!org.apache.commons.lang3.StringUtils.isEmpty(deptIds)) {
        		deptIds = deptIds.substring(0, deptIds.length()-1);
        	}
    		if(!org.apache.commons.lang3.StringUtils.isEmpty(deptIds)) {
    			if(!org.apache.commons.lang3.StringUtils.isEmpty(whereCountBasicSql)) {
    				whereCountBasicSql += " or d.id in ("+deptIds+") ";
    			} else {
    				whereCountBasicSql += " and d.id in ("+deptIds+") ";
    			}
    		}
        	if(org.apache.commons.lang3.StringUtils.isEmpty(whereCountBasicSql)) {
        		whereCountBasicSql += " and 1!=1 ";
    		}
    	}
    	return whereCountBasicSql;
    }

}

